﻿using mozhi.smarterp.Finance.Enums;
using mozhi.smarterp.Finance.Treasuries.Repositories;
using mozhi.smarterp.Finance.Treasuries.Services;
using Mozhi.Abp.Domain.BasicData.Repositories;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;

namespace mozhi.smarterp.Finance.Treasuries.Payments
{
    public class PaymentAppService : FinanceAppService, IPaymentAppService
    {
        private IPaymentRepository _repository;
        private PaymentManager _manager;
        private ICurrencyRepository _currencyRepository;
        private ISupplierRepository _supplierRepository;
        private IEmployeeRepository _employeeRepository;

        public PaymentAppService(PaymentManager manager , IPaymentRepository repository)
        {
            _manager = manager;
            _repository = repository;
        }


        public async Task<PaymentDto> CreateAsync(PaymentCreateDto input)
        {
            var payment = await _manager.GetAsync(null, input.Date, input.BankAccountId, input.SupplierId, input.EmployeeId, input.CustomerId, input.TradingPartnerType, input.CurrencyId,
                input.ExchangeRate, input.IsAdvanced, input.IsRefund, input.Comment , DocumentStatusType.Creation);

            input.Items = input.Items ?? new List<PaymentItemCreateDto>();

            var paymentItems = new List<PaymentItem>();
            foreach (var item in input.Items)
            {
                var paymentItem = await _manager.GetItemAsync(null ,  item.AmountFr , item.Amount ,item.Remark);

                paymentItems.Add(paymentItem);
            }

            payment.SetItems(paymentItems);

            payment = await _repository.InsertAsync(payment);

            var result= ObjectMapper.Map<Payment , PaymentDto>(payment);

            await LoadOtherInfoAsync(new List<PaymentDto>() { result });

            return result;
        }

        public async Task DeleteAsync(Guid id)
        {
            throw new NotImplementedException();
        }

        public async Task<PaymentDto> GetAsync(Guid id)
        {
            var payment = await _repository.GetAsync(id);

            var result = ObjectMapper.Map<Payment, PaymentDto>(payment);

            await LoadOtherInfoAsync(new List<PaymentDto>() { result });

            return result;
        }

        public async Task<PagedResultDto<PaymentDto>> GetListAsync(PaymentPagedResultRequestDto filter)
        {
            var payments = await _repository.GetPagedListAsync(filter.Keyword, filter.Type, filter.IsAdvance, filter.StartDate, filter.EndDate, filter.BankAccountId, filter.CurrencyId,
                filter.MaxResultCount, filter.SkipCount, filter.Sorting);

            var count = await _repository.GetCountAsync(filter.Keyword, filter.Type, filter.IsAdvance, filter.StartDate, filter.EndDate, filter.BankAccountId, filter.CurrencyId , null);

            var items = ObjectMapper.Map<List<Payment>, List<PaymentDto>>(payments);

            await LoadOtherInfoAsync(items);

            return new PagedResultDto<PaymentDto> { Items = items, TotalCount = count };
        }

        public async Task<PaymentDto> UpdateAsync(PaymentUpdateDto input)
        {
            var payment = await _manager.GetAsync(input.Id, input.Date, input.BankAccountId, input.SupplierId, input.EmployeeId, input.CustomerId, input.TradingPartnerType, input.CurrencyId,
                input.ExchangeRate, input.IsAdvanced, input.IsRefund, input.Comment, DocumentStatusType.Creation);

            input.Items = input.Items ?? new List<PaymentItemUpdateDto>();

            var paymentItems = new List<PaymentItem>();
            foreach (var item in input.Items)
            {
                var paymentItem = await _manager.GetItemAsync(null, item.AmountFr, item.Amount, item.Remark);

                paymentItems.Add(paymentItem);
            }

            payment.SetItems(paymentItems);

            payment = await _repository.UpdateAsync(payment);

            var result = ObjectMapper.Map<Payment, PaymentDto>(payment);

            await LoadOtherInfoAsync(new List<PaymentDto>() { result });

            return result;
        }

        #region
        private async Task LoadOtherInfoAsync(List<PaymentDto> payments)
        {
            if (payments.IsNullOrEmpty())
                return;

            foreach (var payment in payments)
            {
                var supplier = payment.SupplierId.HasValue ? await _supplierRepository.GetAsync(payment.SupplierId.Value) : null;
                var employee = payment.EmployeeId.HasValue ? await _employeeRepository.GetAsync(payment.EmployeeId.Value) : null;
                var currency = await _currencyRepository.GetAsync(payment.CurrencyId);

                payment.SupplierName = supplier?.Name;
                payment.EmployeeName = employee?.Name;
                payment.CurrencyName = currency?.Name;
            }
        }
        #endregion
    }
}
